package com.we.tickets.service.Impl;

import com.alibaba.fastjson.JSONObject;
import com.we.tickets.contracts.review.ReviewManagement;
import com.we.tickets.dao.UserDao;
import com.we.tickets.service.ReviewService;
import com.we.tickets.util.CommonUtil;
import com.we.tickets.util.IPFSUtil;
import com.we.tickets.util.constants.Contracts;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.tuples.generated.Tuple5;
import org.web3j.tx.gas.ContractGasProvider;
import org.web3j.tx.gas.StaticGasProvider;

import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;

@Service
public class ReviewServiceImpl implements ReviewService {
    @Autowired
    private UserDao userDao;

    @Autowired
    private Web3j web3j;

    @Override
    public JSONObject addReview(JSONObject jsonObject) {
        String review = jsonObject.getString("comment");
        byte[] reviewByte = review.getBytes(StandardCharsets.UTF_8);
        String hash;
        try {
            hash = IPFSUtil.upload(reviewByte);
        } catch (IOException e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        ReviewManagement reviewManagement;
        try {
            reviewManagement = _getReviewManagement(jsonObject.getInteger("userId"));
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        try {
            reviewManagement.addReview(jsonObject.getBigInteger("LIFEId"), hash, jsonObject.getBigInteger("score")).sendAsync().get();
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        return CommonUtil.successJson();
    }

    @Override
    public JSONObject getEventReviewHashes(JSONObject jsonObject) {
        ReviewManagement reviewManagement;
        try {
            reviewManagement = _getReviewManagement(jsonObject.getInteger("userId"));
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        List<JSONObject> reviews = new ArrayList<>();
        BigInteger num;
        try {
            num = reviewManagement.EventReviewsNumMap(jsonObject.getBigInteger("eventId")).sendAsync().get();
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        for (int i = 0; num.compareTo(BigInteger.valueOf(i)) > 0; i++) {
            Tuple5<BigInteger, String, String, BigInteger, BigInteger> res;
            try {
                res = reviewManagement.EventReviewsMap(jsonObject.getBigInteger("eventId"), BigInteger.valueOf(i)).sendAsync().get();
            } catch (Exception e) {
                e.printStackTrace();
                return CommonUtil.errorJson("操作失败");
            }
            JSONObject review = userDao.getUserInfoByAddress(res.component2());
            review.put("ticketId", res.component1());
            review.put("score", res.component4());
            review.put("datetime", new Date(res.component5().longValue() * 1000));
            byte[] comment;
            try {
                comment = IPFSUtil.load(res.component3());
            } catch (IOException e) {
                e.printStackTrace();
                return CommonUtil.errorJson("操作失败");
            }
            review.put("comment", new String(comment));
            reviews.add(review);
        }
        return CommonUtil.successJson(reviews);
    }

    @NotNull
    private ReviewManagement _getReviewManagement(int id) throws InterruptedException, ExecutionException {
        String privateKey = userDao.getUserPrivateKeyById(id);
        Credentials credentials = Credentials.create(privateKey);
        ContractGasProvider contractGasProvider = new StaticGasProvider(BigInteger.valueOf(20000000000L), BigInteger.valueOf(6721975L));
        ReviewManagement reviewManagement = ReviewManagement.load(Contracts.ReviewManagement ,web3j, credentials, contractGasProvider);
        return reviewManagement;
    }
}
